package top.gokzzz.serialnumber.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.gokzzz.common.utils.DTUtil;
import top.gokzzz.common.utils.StrUtil;
import top.gokzzz.serialnumber.dao.SerialNumberConfigDao;
import top.gokzzz.serialnumber.entity.SerialNumberConfig;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 流水號生成
 *
 * @author Gok
 * @version 1.0
 */
@Component
public class SerialNumberGenerator implements CommandLineRunner {

    private static final Logger LOG = LoggerFactory.getLogger(SerialNumberGenerator.class);

    private final SerialNumberConfigDao configDao;

    @Autowired
    public SerialNumberGenerator(SerialNumberConfigDao serialNumberConfigDao) {
        this.configDao = serialNumberConfigDao;
    }

    @Override
    public void run(String... args) {
        // TODO 初始化 TEST 类型的流水号配置
        initSerialNumberConfig(SerialNumberConfig.Type.TEST, "TEST-{DATE}-{SEQ}", "yyyyMMdd", 5);
    }


    /**
     * 生成流水號
     *
     * @param type 流水號類型
     * @return 生成的流水號
     */
    @Transactional
    public synchronized String generate(SerialNumberConfig.Type type) {
        SerialNumberConfig config = configDao.findByType(type);

        if (config == null) throw new IllegalArgumentException("No configuration found for type: " + type);

        // 更新當前序號
        config.setSeq(config.getSeq() + 1);
        // 生成流水號
        String serialNumber = generateSerialNumber(config);

        configDao.save(config);

        return serialNumber;
    }

    /**
     * 根據配置生成流水號
     *
     * @param config 流水號配置
     * @return 生成的流水號
     */
    private String generateSerialNumber(SerialNumberConfig config) {
        String dateFormat = DTUtil.parse(LocalDateTime.now(), config.getDateFormat());

        String seqStr = String.format("%0" + config.getSeqLength() + "d", config.getSeq());

        Map<String, Object> params = new HashMap<>();
        params.put("SEQ", seqStr);
        params.put("DATE", dateFormat);

        return StrUtil.format(config.getFormat(), params);
    }

    /**
     * 初始化流水號配置
     *
     * @param type       流水號類型
     * @param format     流水號格式
     * @param dateFormat 日期格式
     * @param seqLength  序列號長度
     */
    private void initSerialNumberConfig(SerialNumberConfig.Type type, String format, String dateFormat, int seqLength) {
        SerialNumberConfig config = configDao.findByType(type);
        if (config == null) {
            config = new SerialNumberConfig();
            config.setType(type);
            config.setFormat(format);
            config.setDateFormat(dateFormat);
            config.setSeqLength(seqLength);
            config.setSeq(0L);
            configDao.save(config);
            LOG.info("========================New serial number config created for type: {}====================================", type);
        }
    }
}
